using UnityEngine;
using System.Collections;
using System.Collections.Generic;

/// \class  gkRhythmSynchronizer
/// \brief  Helper to synchronize action with rhythms
[AddComponentMenu("GK/Engine/Game/Rhythm/gkRhythmSynchronizer")]
public class gkRhythmSynchronizer : MonoBehaviour 
{
	/// beat per minute
	public int BeatsPerMinute = 60;
	
	/// The rhythms to synchronize with
	private Dictionary<string, gkRhythm> m_oRhythmsByName = new Dictionary<string, gkRhythm>();
	
	/// The number of beat since start
	private int m_iNbBeatsSinceStart;
	
	/// The time elapsed since the last beat
	private float m_fTimeElapsedSinceLastBeat;
	
	/// \brief  Called on script load
	void Awake()
	{
		// Fill the dictionnary of rhythms with the initial rhythms
		// attached to the owner
		foreach(gkRhythm rRhythm in GetComponents<gkRhythm>())
		{
			m_oRhythmsByName.Add(rRhythm.Name, rRhythm);
		}
	}
	
	/// \brief  Called each frame
	void Update()
	{
		UpdateBeat();
	}
	
	/// \brief  Update the beat
	void UpdateBeat()
	{
		int iNbBeatDuringUpdate;
		float fBeatsPerSecond;
			
		// Keep track of time since last beat
		m_fTimeElapsedSinceLastBeat += Time.deltaTime;
		
		// Convert the beat per minutes in beat per seconds
		fBeatsPerSecond = BeatsPerMinute/60.0f;
		
		// Count if we have a beat during this update and how much
		iNbBeatDuringUpdate = (int)(m_fTimeElapsedSinceLastBeat * fBeatsPerSecond);
		
		if(iNbBeatDuringUpdate != 0.0f)
		{
			// Count the number of beats since start
			m_iNbBeatsSinceStart += iNbBeatDuringUpdate; 
			
			// Update the time elasped since last beat
			m_fTimeElapsedSinceLastBeat -= iNbBeatDuringUpdate / fBeatsPerSecond;
		}
	}
	
	/// \brief  Call an event on a rythm start
	public void RaiseEventOnRythmStart(string a_strRhythmName, gkEventComponent a_rEventComponent, string a_strEventName, 
	                                   Object a_rEvent = null)
	{
		gkRhythm rRhythm;
		
		// Try to get the rhythm by name
		if(m_oRhythmsByName.TryGetValue(a_strRhythmName, out rRhythm))
		{
			float fNbRhythmSinceStart;
			float fCurrentRhythmCompletionPercent;
			float fTimeRemainingBeforeNextRhythmStart;
			float fBeatsPerSecond;
			float fNbBeatsSinceStart;
		
			// Convert the beat per minutes in beat per seconds
			fBeatsPerSecond = BeatsPerMinute/60.0f;
			
			// Compute the delay at which called the event to be on the next rhythm start
			fNbBeatsSinceStart = m_iNbBeatsSinceStart + m_fTimeElapsedSinceLastBeat * fBeatsPerSecond;
			fNbRhythmSinceStart = fNbBeatsSinceStart / rRhythm.DurationInBeat;
			fCurrentRhythmCompletionPercent = fNbRhythmSinceStart - (int)fNbRhythmSinceStart;
			fTimeRemainingBeforeNextRhythmStart =  (1.0f - fCurrentRhythmCompletionPercent) * rRhythm.DurationInBeat * fBeatsPerSecond;
			
			a_rEventComponent.RaiseDelayedEvent(fTimeRemainingBeforeNextRhythmStart, a_strEventName, a_rEvent);
		}
	}
}